package runtime_area

import (
	"jvm/nzpJvm/runtime_area/heap"
	"math"
)

// 操作数栈，每个操作数都占一个或者两个槽位
type OprandStack struct {
	size  uint
	slots []Slot
}

func newOperandStack(maxStack uint) *OprandStack {
	if maxStack == 0 {
		return nil
	}
	return &OprandStack{
		slots: make([]Slot, maxStack),
	}
}

func (self *OprandStack) PushInt(val int32) {
	self.slots[self.size].num = val
	self.size++
}

func (self *OprandStack) PopInt() int32 {
	self.size--
	return self.slots[self.size].num
}

func (self *OprandStack) PushFloat(val float32) {
	self.slots[self.size].num = int32(math.Float32bits(val))
	self.size++
}

func (self *OprandStack) PopFloat() float32 {
	self.size--
	return math.Float32frombits(uint32(self.slots[self.size].num))
}
func (self *OprandStack) PushLong(val int64) {
	self.slots[self.size].num = int32(val)
	self.slots[self.size+1].num = int32(val >> 32)
	self.size += 2
}

func (self *OprandStack) PopLong() int64 {
	self.size -= 2
	low := uint32(self.slots[self.size].num)
	high := uint32(self.slots[self.size+1].num)
	return int64(high)<<32 | int64(low)
}
func (self *OprandStack) PushDouble(val float64) {
	self.PushLong(int64(math.Float64bits(val)))
}

func (self *OprandStack) PopDouble() float64 {
	long := self.PopLong()
	return math.Float64frombits(uint64(long))
}

func (self *OprandStack) PushRef(val *heap.Object) {
	self.slots[self.size].ref = val
	self.size++
}

func (self *OprandStack) PopRef() *heap.Object {
	self.size--
	ref := self.slots[self.size].ref
	self.slots[self.size].ref = nil // 垃圾回收
	return ref
}

func (self *OprandStack) PushSlot(val Slot) {
	self.slots[self.size] = val
	self.size++
}

func (self *OprandStack) PopSlot() Slot {
	self.size--
	ref := self.slots[self.size]
	return ref
}

// 获取距离栈顶指定距离的槽位的值
func (self *OprandStack) GetRefFromTop(count uint) *heap.Object {
	return self.slots[self.size-count].ref
}
